/*! \file component.cpp
	
	This contains the implementation of the Component class
*/

#include <GL/glfw.h>
#include "component.h"
#include "guiclass.h"
#include "listener.h"
#include "container.h"
#include <iostream>

using namespace std;


Component::Component( Component* parent ) :
	parent(0),
	x(50),
	y(50),
	w(50),
	h(50),
	mouseIsOver(false),
	mouseIsDown(false),
	sideID1(-1),
	cornerID1(-1),
	visible(true)
	{
		setBorder( false );
		this->parent = parent;
		setDefaultGUIStyle();
		// When we create any component, we need to let its parent know that we created it.
		// If the parent CAN add this object, then it will add it.
		// The main GUI and Containers can add, so we check for those
		// NOTE: HoverText does not have a parent, so it is never added to anything, so that's
		// why we check to see if a parent exists at all.
		if ( parent ) {
			if ( parent->getType() == TYPE_GUI ) {
				GUI::getInstance()->add( this );
			} else if ( parent->getType() == TYPE_CONTAINER ) {
				((Container*)parent)->add( this );
			}
		}
		id = GUI::nextAvailableID();
		//~ cout << "Making this ID: " << id << endl;
	}
void Component::setGUIStyle( int unfocusedSideID, int unfocusedCornerID, int focusedSideID, int focusedCornerID ) {
	sideID1 = unfocusedSideID;
	sideID2 = focusedSideID;
	cornerID1 = unfocusedCornerID;
	cornerID2 = focusedCornerID;
	
	int discard;
	ImageHandler::getInstance()->getImageSize( borderWidth, discard, sideID1 );
}
void Component::setPosition( int newX, int newY ) {
	x = newX;
	y = newY;
}

void Component::setSize( int newWidth, int newHeight ) {
	w = newWidth;
	h = newHeight;
	vector<Listener*>::iterator j;
	for ( j = listeners.begin(); j != listeners.end(); ++j ) {
		(*j)->onSize( Event( this ) );
	}
	if ( this != GUI::getInstance() && parent != GUI::getInstance() ) {
		((Container*)parent)->childChangedSize( this );
	}
}


void Component::setWidth( int newWidth ) {
	setSize( newWidth, h );
}

void Component::setHeight( int newHeight ) {
	setSize( w, newHeight );
}

void Component::addListener( Listener* l ) {
	listeners.push_back( l );
}

int Component::getX() { return x; }
int Component::getY() { return y; }

int Component::getScreenX() {
	// Parent is 0 for HoverText
	if ( parent == 0 || this == GUI::getInstance() ) {
		return x;
	}
	return x + parent->getScreenX();
}

int Component::getScreenY() {
	// Parent is 0 for HoverText
	if ( parent == 0 || this == GUI::getInstance() ) {
		return y;
	}
	return y + parent->getScreenY();
}

void Component::setID( int ID ) { 
	id = ID;
}

int Component::getID() { return id; }

bool Component::handleMouseWheel( int pos ) {
	if ( !visible ) {
		return false;
	}
	vector<Listener*>::iterator j;
	for ( j = listeners.begin(); j != listeners.end(); ++j ) {
		(*j)->onScroll( Event( this, pos ) );
	}
	// return true regardless of whether this component has listeners or not
	return true;
}

bool Component::handleMouseMove( int mX, int mY ) {
	if ( !visible ) {
		return false;
	}
	glfwGetMousePos( &mX, &mY );
	// Make the coordinates relative to the upper left of the component
	mX -= getScreenX();
	mY -= getScreenY();
	if ( mX >= 0 && mX <= w && mY >= 0 && mY <= h ) {
		// Go through all of the listeners and trigger their onEnter events
		if ( mouseIsOver == false ) {
			vector<Listener*>::iterator j;
			for ( j = listeners.begin(); j != listeners.end(); ++j ) {
				(*j)->onEnter( Event( this ) );
			}
			mouseIsOver = true;
		}	
		return true;
	} else {
		if ( mouseIsOver ) {
			vector<Listener*>::iterator j;
			for ( j = listeners.begin(); j != listeners.end(); ++j ) {
				(*j)->onLeave( Event( this ) );
			}
		}
		mouseIsOver = false;
	}
	return false;
}

bool Component::handleMouseClick( int button, int state ) {
	if ( !visible ) {
		return false;
	}
	int mX, mY;
	glfwGetMousePos( &mX, &mY );
	// Make the coordinates relative to the upper left of the component
	mX -= getScreenX();
	mY -= getScreenY();
	bool handled = false;
	//~ cout << "This pos: (" << x << ", " << y << ") and mouse pos: (" << mX << ", " << mY << ")" << endl;
	if ( mX >= 0 && mX <= w && mY >= 0 && mY <= h ) {
		if ( state == GLFW_PRESS ) {
			// This will now be the focus regardless of whether this has listeners
			((Container*)parent)->setFocus( this );
		}
		//~ cout << "Set focus to whatever this is " << endl;
		//~ setBackgroundColor( Color(1.0f ), Color(1.0f) );
		vector<Listener*>::iterator j;
		for ( j = listeners.begin(); j != listeners.end(); ++j ) {
			if ( state == GLFW_PRESS ) {
				mouseIsDown = true;
				handled = true;
				(*j)->mouseDown( Event( this ) );
			}
		}
	}
	if ( mouseIsDown && state == GLFW_RELEASE ) {
		sendMouseUpEvent();
	}
	return handled;
	
}

void Component::sendMouseUpEvent() {
	//~ cout << "Sending mouse up event " << endl;
	mouseIsDown = false;
	vector<Listener*>::iterator j;
	for ( j = listeners.begin(); j != listeners.end(); ++j ) {
		(*j)->mouseUp( Event( this ) );
	}
}

void Component::sendOnLeaveEvent() {
	//~ cout << "Sending mouse leave event " << endl;
	mouseIsOver = false;
	vector<Listener*>::iterator j;
	for ( j = listeners.begin(); j != listeners.end(); ++j ) {
		(*j)->onLeave( Event( this ) );
	}
}

void Component::handleKeyInput( int key, int state ) {
	if ( !visible ) {
		return;
	}
	vector<Listener*>::iterator j;
	for ( j = listeners.begin(); j != listeners.end(); ++j ) {
		if ( state == GLFW_PRESS ) {
			(*j)->keyDown( Event( this, key ) );
		}
	}
	if ( state == GLFW_RELEASE ) {
		vector<Listener*>::iterator j;
		for ( j = listeners.begin(); j != listeners.end(); ++j ) {
			(*j)->keyUp( Event( this, key ) );
		}
	}
}

void Component::setBorder( bool enabled ) {
	border = enabled;
	if ( !enabled ) {
		borderWidth = 0;
	}
}
void Component::setVisible( bool visibility ) {
	visible = visibility;
}
bool Component::canHaveFocus() {
	return true;
}

bool Component::isVisible() {
	return visible;
}

int Component::getType() {
	return TYPE_COMPONENT;
}

void Component::setX( int newX ) {
	x = newX;
}

void Component::setY( int newY ) {
	y = newY;
}

int Component::getWidth() {
	return w;
}
int Component::getHeight() {
	return h;
}

void Component::setBackgroundColor( Color top, Color bottom ) {
	bgColorTop = top;
	bgColorBottom = bottom;
}

void Component::setDefaultGUIStyle() {
	bgColorTop = Color( 1.0f, 1.0f, 1.0f, 1.0f );
	bgColorBottom = Color( .92f, .92f, .92f, 1.0f );
	//~ bgColorTop = Color( 1.0f, 0.0f, 0.0f, 1.0f );
	//~ bgColorBottom = Color( 0.0f, 1.0f, 0.0f, 1.0f );
	setGUIStyle( 6, 7, 8, 9 );
}
	
int Component::getBorderWidth() {
	return borderWidth;
}
